/*
 * SpiderpigOS
 * Copyright (C) 2009 - 2010 Davide Gessa
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <shell.h>
#include <klibc/stdio.h>
#include <klibc/string.h>
#include <arch.h>
#include <kernel.h>
#include <driver.h>
#include <config.h>
#include <klibc/malloc.h>
#include <mm/mm.h>


/* commands list */
bish_cmd_t bish_cmd_list[] = 
	{
		{ .func = &bish_help,		.name = "help\0",		.desc = "show commands help"},
		{ .func = &bish_true,		.name = "true\0",		.desc = "return true"},
		{ .func = &bish_false,		.name = "false\0",		.desc = "return false"},
		{ .func = &bish_set, 		.name = "set\0",		.desc = "variable ops"},
		{ .func = &bish_unset,		.name = "unset\0",		.desc = "unset a variable"},
		{ .func = &bish_memstat,	.name = "memstat\0",	.desc = "memory stat"},
		{ .func = &bish_shutdown,	.name = "shutdown\0",	.desc = "shutdown the pc"},
		{ .func = &bish_sysinfo,	.name = "sysinfo\0",	.desc = "print system info"},
		{ .func = &bish_reboot,		.name = "reboot\0",		.desc = "reboot the pc"},
		{ .func = &bish_datetime,	.name = "datetime\0",	.desc = "print date and time"},

		{ .func = NULL,				.name = "\0",			.desc = "\0" }
	};
	

char *argv[32];

	
/* start shell */
void 
shell()
{
	char while_c = 1;
	char buf[1024];
	int x;
	int state;
	
	for(x = 0; x < 32; x++)
		argv[x] = (char *) malloc(128);
	
	
	/* clean all variables */
	for(x = 0; x < BISH_VAR_NUM; x++)
	{
		strcpy(bish_var_list[x].name, "\0");
		strcpy(bish_var_list[x].value, "\0");
	}


	strcpy(bish_var_list[0].name, "CUR_DIR\0");
	strcpy(bish_var_list[0].value, "/\0");
	
	strcpy(bish_var_list[1].name, "PATH\0");
	strcpy(bish_var_list[1].value, "/bin\0");
		
	printf("\n");
		
	/* mainloop */
	while(while_c)
	{
		arch_ksetcl(0x09);
		printf("pigsh$ ");
		arch_ksetcl(0x0F);
		
		int i = 0;
		while((buf[i] = getchar()) != '\n')
		{
			if(buf[i] == '\t')
			{
				char tmp[128];
				buf[i] = 0;
				strcpy(tmp, buf);
				for(x = 0; x < BISH_CMD_NUM; x++)
				{
					if(strncmp(bish_cmd_list[x].name, tmp,strlen(tmp)) == 0)
					{
						puts(bish_cmd_list[x].name+strlen(tmp));
						strcpy(buf, bish_cmd_list[x].name);
						i = strlen(buf);
						break;
					}
				}
			}
			else
				putchar(buf[i]);

			i++;
		}
		buf[i] = 0;
		printf("\n");

		if(buf[0] == '\0') continue;
		strcpy(argv[0], "\0");
		
		state = bish_parse_command(buf);
		
		if(strcmp("exit\0", buf) == 0)
			while_c = 0;
		else if(state == -1) 
			printf("command not found\n");
	}
}



/* parse a command */
int 
bish_parse_command(char *buf)
{
	int state;
	int argc;
	int x;
	
	/* arg split */
	argc = 0;
	x = 0;
	int buf_c = 0;

	while(buf[x] != '\0')
	{
		argv[argc][buf_c] = buf[x];
			
		x++;
		buf_c++;
			
		if((buf[x] == ' ') || (buf[x] == '\0'))
		{
			argv[argc][buf_c] = '\0';
			argc++;
			buf_c = 0;
			if(buf[x] == '\0') break;
			x++;
		}
	}
	
	state = -1;


	for(x = 0; x < BISH_CMD_NUM; x++)
	{
		if(strcmp(bish_cmd_list[x].name, argv[0]) == 0)
		{
			state = bish_cmd_list[x].func(argc, &argv[0]);
			break;
		}
	}
		
	return state;	
}





/* clean the screen */
int 
bish_clear(int argc, char **argv)
{
	arch_kclear();
	return 0;
}





/* help message */
int 
bish_help(int argc, char **argv)
{
	if(argc == 0 || argc == 1)
	{
		printf("pighsell\naviable commands: ");
	}
	
	if((argc == 2) && (strcmp(argv[1], "-l") == 0))
	{
		int x, i, t;
		
		i = 0;
		for(x = 0; x < BISH_CMD_NUM; x++)
		{
			if(bish_cmd_list[x].name[0] != '\0')
				printf("%s - %s\n", bish_cmd_list[x].name, bish_cmd_list[x].desc);
			else break;
			i++;
			if(i > 20)
			{
				i = 0;
				printf("press return...\n");
				scanf("%d", &t);
			}
		}			
	}
	else if(argc == 1)
	{
		int x;
		
		printf("\n");
		for(x = 0; x < BISH_CMD_NUM; x++)
		{
			if(bish_cmd_list[x].name[0] != '\0')
				printf("%s ", bish_cmd_list[x].name);
			else break;
		}	
		
		printf("\n");
		return 0;
	}
	
	else if(argc >= 2)
	{
		int x;
		
		for(x = 0; x < BISH_CMD_NUM; x++)
		{
			if(argv[1][0] == '%' && bish_cmd_list[x].name[0] != '\0') 
				printf("%s - %s\n", bish_cmd_list[x].name, bish_cmd_list[x].desc);
			else if(strcmp(argv[1], bish_cmd_list[x].name) == 0)
			{
				printf("%s - %s\n", argv[1], bish_cmd_list[x].desc);
				return 0;
			}
		}
		
		if(argv[1][0] == '%') 
			return 0;
			
		printf("command %s not found\n", argv[1]);
		return 1;
	}
	
	return 0;
}




/* true */
int 
bish_true(int argc, char **argv)
{
	return 1;
}



/* false */
int 
bish_false(int argc, char **argv)
{
	return 0;
}


/* memory stat */
int 
bish_memstat(int argc, char **argv)
{
	printf("used: %dkb ", mm_get_used_mem());
	#ifndef ARCH_ARM
		printf("(%d%%)", mm_get_used_mem() * 100 / mm_get_total_mem());
	#endif
	printf("\ntotal: %dkb\n", mm_get_total_mem());
	return 0;
}



/* shutdown the pc */
int 
bish_shutdown(int argc, char **argv)
{
	shutdown(1);
	return 0;
}


/* reboot the pc */
int bish_reboot(int argc, char **argv)
{
	shutdown(2);
	return 0;
}


/* variable operations */
int 
bish_set(int argc, char **argv)
{
	if(argc == 1)
	{
		int x;
		for(x = 0; x < BISH_VAR_NUM; x++)
		{
			if(strcmp(bish_var_list[x].name, "\0") != 0)
				printf("%s=%s\n", bish_var_list[x].name, bish_var_list[x].value);
		}
	}

	return 0;
}




/* remove a variable */
int 
bish_unset(int argc, char **argv)
{
	if(argc == 2)
	{
		int x;
		for(x = 0; x < BISH_VAR_NUM; x++)
		{
			if(strcmp(bish_var_list[x].name, argv[1]) == 0)
			{
				strcpy(bish_var_list[x].name, "\0");
				strcpy(bish_var_list[x].value, "\0");
				
				return 0;
			}
		}
		
		printf("variable %s not found\n", argv[1]);
		return 1;
	}
	return 0;
}




/* show system info */
int 
bish_sysinfo(int argc, char **argv)
{
	printf("%s %s (rev %d on %s)\n", NAME, RELEASE_NAME, REVISION, ARCH);
	
	return 0;
}



/* show date and time */
int 
bish_datetime(int argc, char **argv)
{
	printf("%d/%d/%d %d:%d:%d\n", clock_data.day, clock_data.month, clock_data.year+2000,
			clock_data.hours, clock_data.minutes, clock_data.seconds);
	
	return 0;
}
